<?php if( !defined('BASEPATH')) exit('No access!');

class C_Model extends CI_Model {

    //继承基类model，必须重写这四个值
    protected $table_name = '';//表名
    protected $order_by = '';//排序
    protected $insert_noneed_fields = array();//不需要插入数据的字段
    protected $update_noneed_fields = array();//不需要更新数据的字段

    //构造函数V
    public function __construct()
    {
        //开启session
        if(!isset($_SESSION))
        {
            session_start();
        }
        parent::__construct();
        $this->load->database();
    }

    /**
     * 综合查询函数
     * 区别点：用于数据统计、分页等，对select的字段进行转义
     * @param  array $arr      综合数组
     * @param  string $field   查询字段
     * @param  int $limit    limit
     * @param  int $offset   offset
     * @param  string $order_by 排序
     * @return [type]           [description]
     */
    public function get($arr, $field = '*', $limit = 0, $offset = 0, $order_by = '')
    {
        if(!$this->check_get_fields($field)){
            return array();
        }

        if($field == '*'){
            $this->db->select($this->get_all_fields());
        }else{
            $this->db->select($field);
        }

        $order_by = $order_by == '' ? $this->order_by : $order_by;
        $this->splice_where($arr);
        $this->db->order_by($order_by);
        if($limit === 0)
        {
            $q = $this->db->get($this->table_name);
        }
        else
        {
            $q = $this->db->get($this->table_name, $limit, $offset);
        }
        // echo $this->db->last_query();echo '<br>';
        // echo $this->db->last_query();die();
        return $q->result_array();
    }

    /**
     * 综合查询函数
     * 区别点：用于数据统计、分页等，不对select的字段进行转义
     * @param  array $arr      综合数组
     * @param  string $field   查询字段
     * @param  int $limit    limit
     * @param  int $offset   offset
     * @param  string $order_by 排序
     * @return [type]           [description]
     */
    public function special_get($arr, $field = '*', $limit = 0, $offset = 0, $order_by = '')
    {
        if($field == '*'){
            $this->db->select($this->get_all_fields(),true);
        }else{
            $this->db->select($field,false);
        }
        $order_by = $order_by == '' ? $this->order_by : $order_by;
        $this->splice_where($arr);
        $this->db->order_by($order_by);
        if($limit === 0)
        {
            $q = $this->db->get($this->table_name);
        }
        else
        {
            $q = $this->db->get($this->table_name, $limit, $offset);
        }
        return $q->result_array();
    }

    /**
     * 获取一条记录
     * @param $arr 查询条件综合数组
     * @param $field 查询的字段
     */
    public function get_row($arr, $field = '*')
    {
        if(!$this->check_get_fields($field)){
            return array();
        }

        if($field == '*'){
            $this->db->select($this->get_all_fields());
        }else{
            $this->db->select($field);
        }
        $this->splice_where($arr);
        $q = $this->db->get($this->table_name);
        return $q->row_array();
    }

    /**
     * 通过sql语句 获取数据
     * 注意：
     * 需要用sql语句进行查询时，在数据库语句中，要对必要字段进行过滤
     * 1、对普通字段进行过滤 $this->db->escape($str);
     * 2、在where语句使用like模糊查询 $this->db->escape_like_str($str);
     *
     */
    public function get_by_sql($sql = ''){
        if($sql == ''){
            return false;
        }
        $q = $this->db->query($sql);
        return $q->result_array();
    }

    /**
     * 获取该数据表的所有字段
     * @return array
     */
    public function get_columns(){
        return $this->db->list_fields($this->table_name);
    }
    /**
     * 获取该数据表的所有字段，用于查询时 * 转换字段
     * @return string
     */
    public function get_all_fields(){
        $fileds = $this->get_columns();
        return implode(',', $fileds);
    }
    /**
     * 通过条件获取该条件下的总数
     * @param $arr 查询条件综合数组
     * @param string 单个字段
     */
    public function get_by_where_count_num($arr,$field = ''){
        if($field == ''){
            $this->splice_where($arr);
            $this->db->from($this->table_name);
            return $this->db->count_all_results();
        }else{
            if(count(explode(',', $field)) > 1){
                return false;
            }
            $this->splice_where($arr);
            $this->db->select("count({$field}) total_count");
            $q =$this->db->get($this->table_name);
            $res = $q->row_array();
            if($res && isset($res['total_count'])){
                return $res['total_count'];
            }else{
                return 0;
            }
        }

    }
    /**
     * 通过条件获取该条件下的总和
     * @param $arr 查询条件综合数组
     * @param string 单个字段
     */
    public function get_by_where_sum($arr,$field){
        if(count(explode(',', $field)) > 1){
            return false;
        }
        $this->splice_where($arr);
        $this->db->select("sum({$field}) total_sum");
        $q =$this->db->get($this->table_name);
        $res = $q->row_array();
        if($res && isset($res['total_sum'])){
            return $res['total_sum'];
        }else{
            return 0;
        }

    }

    /**
     * 拼接where条件
     */
    public function splice_where($arr){
        foreach ($arr as $key => $value)
        {
            switch ($value[0])
            {
                case 'where':
                    $this->db->where($value[1]);
                    break;
                case 'condition':
                    $this->db->where($value[1]);
                    break;
                case 'where_string':
                    $this->db->where($value[1]);
                    break;
                case 'or_where':
                    $this->db->or_where($value[1]);
                    break;
                case 'where_in':
                    $this->db->where_in($value[1], $value[2]);
                    break;
                case 'or_where_in':
                    $this->db->or_where_in($value[1], $value[2]);
                    break;
                case 'where_not_in':
                    $this->db->where_not_in($value[1], $value[2]);
                    break;
                case 'or_where_not_in':
                    $this->db->or_where_not_in($value[1], $value[2]);
                    break;
                case 'like':
                    $this->db->like($value[1]);
                    break;
                case 'or_like':
                    $this->db->or_like($value[1]);
                    break;
                case 'not_like':
                    $this->db->not_like($value[1]);
                    break;
                case 'or_not_like':
                    $this->db->or_not_like($value[1]);
                    break;
                case 'group_by':
                    $this->db->group_by($value[1]);
                    break;
                default:
                    # code...
                    break;
            }
        }
        //判断存不存在where条件
        if(count($this->db->ar_where) <= 0 && count($this->db->ar_like) <= 0){
            return false;
        }
        return true;
    }

    /**
     * 判断查询的字段是否合法
     * @param $fields 字段英文,隔开
     */
    public function check_get_fields($fields = ''){
        if($fields == ''){
            return false;
        }
        if($fields == '*'){
            return true;
        }
        $fields = explode(',', $fields);
        if(!is_array($fields)){
            return false;
        }
        if(count(array_diff($fields, $this->get_columns())) != 0) {
            return false;
        }
        return true;
    }
    /**
     * 判断插入数据的字段是否合法
     * @param $data 插入的数据 example array('insert_column' => 'insert_value')
     */
    public function check_insert_data($data){
        if(!isset($data) || count($data)<=0){
            return false;
        }
        if(empty($this->insert_noneed_fields)){
            $insert_fields = array_diff($this->get_columns(), $this->insert_noneed_fields);
        }
        //获取插入所需要的字段
        $insert_fields = array_diff($this->get_columns(), $this->insert_noneed_fields);
        if(is_array($data[key($data)])){
            $flag = true;
            foreach ($data as $key => $value) {
                if(count(array_diff(array_keys($value), $insert_fields)) > 0){
                    $flag = false;
                    break;
                }
            }
            return $flag;
        }else{
            if(count(array_diff(array_keys($data), $insert_fields)) > 0){
                return false;
            }
        }
        return true;
    }
    /**
     * 判断更新数据的字段是否合法
     * @param $data 更新的数据 example array('update_column' => 'update_value')
     */
    public function check_update_data($data){
        if(!isset($data) || count($data)<=0){
            return false;
        }
        //获取更新所需要的字段
        $update_fields = array_diff($this->get_columns(), $this->update_noneed_fields);

        if(is_array($data[key($data)])){
            foreach ($data as $key => $value) {
                if(count(array_diff(array_keys($value), $update_fields)) > 0){
                    return false;
                }
            }
        }else{
            if(count(array_diff(array_keys($data), $update_fields)) > 0){
                return false;
            }
        }
        return true;
    }
    /**
     * 过滤更新的字段
     * @param $filter_data 更新的数据
     * @param $update_column 对比的字段，一般为数据表的全部字段
     */
    public function filter_update($filter_data = null,$update_column = null){
        if(!$filter_data || !$update_column)
            return false;
        return array_intersect_key($filter_data, array_flip($update_column));
    }
    /**
     * 过滤插入的字段
     * @param $filter_data 更新的数据
     * @param $insert_column 对比的字段，一般为数据表的全部字段
     */
    public function filter_insert($filter_data = null,$insert_column = null){
        if(!$filter_data || !$insert_column)
            return false;
        if(is_array($filter_data[key($filter_data)])){
            $flag = true;
            foreach ($filter_data as $k => $v){
                $temp = array_intersect_key($v, array_flip($insert_column));
                if(!$temp){
                    $flag = false;
                    break;
                }else{
                    $filter_data[$k] = $temp;
                }
            }
            if($flag){
                return $filter_data;
            }else{
                return false;
            }
        }else{
            return array_intersect_key($filter_data, array_flip($insert_column));
        }

    }
    /**
     * 插入
     * @param $data example array('update_column' => 'update_value')
     */
    public function insert($data = null){
        if(empty($data)){
            return false;
        }
        //检测字段
        if(!$this->check_insert_data($data)){
            return false;
        }
        $data = $this->filter_insert($data,$this->get_columns());
        if(!$data){
            return false;
        }
        if(is_array($data[key($data)])){
            $this->db->insert_batch($this->table_name, $data);
            return $this->db->affected_rows() >= 0 ? true:false;
        }else{
            $this->db->insert($this->table_name, $data);
            if ($this->db->primary($this->table_name)){
                return $this->db->insert_id() >0 ?$this->db->insert_id():false;
            }else {
                return $this->db->insert_id() >=0?$this->db->insert_id():false;
            }
        }
    }

    /**
     * 更新
     * @param $where example array(array('where' => array('where_column' => 'where_value')))
     * @param $data example array('update_column' => 'update_value')
     */
    public function update($where,$data){
        if(is_null($where) || is_null($data))
            return false;
        if(is_null($this->check_update_data($data)))
            return false;
        $data = $this->filter_update($data,$this->get_columns());
        if(is_null($data))
            return false;
        $this->splice_where($where);

        if(is_array($data[key($data)])){
            $res = $this->db->update_batch($this->table_name, $data);
            return $this->db->affected_rows() >= 0 ? true:false;
        }else{
            $res = $this->db->update($this->table_name, $data);
            if ($this->db->primary($this->table_name)){
                return $this->db->affected_rows() >0 ?true:false;
            }else {
                return $this->db->affected_rows() >=0?true:false;
            }
        }
    }
    //开启事务
    public function trans_begin()
    {
        $this->db->trans_begin();
    }
    //回滚
    public function trans_rollback()
    {
        $this->db->trans_rollback();
    }
    //提交事务
    public function trans_commit()
    {
        $this->db->trans_commit();
    }

}